package com.unlcn.ils.sales.backend.service;

import cn.huiyunche.commons.exception.BusinessException;
import cn.huiyunche.commons.utils.QiniuUtil;
import com.google.common.collect.Lists;
import com.unlcn.ils.sales.backend.bo.BankBO;
import com.unlcn.ils.sales.backend.bo.UserBankCardViewBO;
import com.unlcn.ils.sales.backend.bo.UserBankcardBO;
import com.unlcn.ils.sales.backend.bo.UserViewBO;
import com.unlcn.ils.sales.backend.constant.AutoConfConstant;
import com.unlcn.ils.sales.backend.enums.YeepayCardTypeEnum;
import com.unlcn.ils.sales.backend.enums.YeepayCardValidEnum;
import com.unlcn.ils.sales.backend.util.Encodes;
import com.unlcn.ils.sales.backend.yeepay.utils.PaymobileUtils;
import com.unlcn.ils.sales.base.mapper.SaleUserBankcardMapper;
import com.unlcn.ils.sales.base.model.SaleUserBankcard;
import com.unlcn.ils.sales.base.model.SaleUserBankcardExample;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * Created by houjianhui on 2017/6/8.
 */
@Service
public class UserBankcardServiceImpl implements UserBankcardService {

    private static final Logger LOGGER = LoggerFactory.getLogger(UserBankcardServiceImpl.class);

    private final String BANK_CARD_PREFIX = "**** **** **** ";


    @Autowired
    private SaleUserBankcardMapper userBankcardMapper;

    @Autowired
    private PickPwdService pickPwdService;

    @Autowired
    private BankService bankService;

    @Autowired
    private UserService userService;

    @Autowired
    private AutoConfConstant autoConfConstant;

    @Override
    public Integer save(UserBankcardBO bo) throws Exception {
        LOGGER.info("UserBankcardServiceImpl.save param UserBankcardBO: {}", bo);
        if (Objects.equals(bo, null) || Objects.equals(bo, "")) {
            LOGGER.info("UserBankcardServiceImpl.save param UserBankcardBO must not be null");
            throw new IllegalArgumentException("银行卡信息不能为空");
        }
        UserViewBO user = userService.getCurrentUser();

        bo.setUserId(user.getId());

        // 校验卡信息
        checkBindBankCard(bo);

        // 卡校验
        Map<String, String> map = checkBankCard(bo.getBankCode());

        // 校验密码
        Boolean bool = pickPwdService.verificationPickPwd(bo.getPwd());
        if (!bool) {
            throw new BusinessException("输入提现密码错误，请重新输入");
        }

        // 绑定银行卡
        SaleUserBankcard bankcard = new SaleUserBankcard();
        BeanUtils.copyProperties(bo, bankcard);
        bankcard.setCode(encryptBankCard(bo.getCode()));
        BankBO bankBO = bankService.getBankByCode(map.get("bankcode"));
        bankcard.setBankId(bankBO.getId());
        bankcard.setBankCode(bankBO.getCode());
        bankcard.setBankName(bankBO.getName());
        try {
            return userBankcardMapper.insertSelective(bankcard);
        } catch (Exception e) {
            LOGGER.error("UserBankcardServiceImpl.save error: {}", e);
            throw new BusinessException("绑定银行卡异常");
        }
    }

    @Override
    public List<UserBankCardViewBO> listUserBankcard() throws Exception {
        UserViewBO user = userService.getCurrentUser();
        SaleUserBankcardExample example = new SaleUserBankcardExample();
        example.createCriteria().andUserIdEqualTo(user.getId()).andEnableEqualTo(true).andDeleteMarkEqualTo(false);
        List<SaleUserBankcard> lists = userBankcardMapper.selectByExample(example);
        List<UserBankCardViewBO> bos = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(lists)) {
            lists.stream().forEach(val -> {
                BankBO bankBO = null;
                try {
                    bankBO = bankService.getBankByCode(val.getBankCode());
                } catch (Exception e) {
                    LOGGER.error("The bank information error: {}", e);
                    throw new BusinessException("获取银行信息异常");
                }
                if (Objects.equals(bankBO, null)) {
                    bankBO = new BankBO();
                }
                String code = decryptBankCard(val.getCode());
                String bankLogoBucket = autoConfConstant.getBankLogo();
                String codeKey = BANK_CARD_PREFIX + code.substring(code.length() - 4, code.length());
                bos.add(new UserBankCardViewBO(val.getId(), codeKey , bankBO.getName(), QiniuUtil.generateDownloadURL(bankLogoBucket, bankBO.getLogo(), "", "", ""), QiniuUtil.generateDownloadURL(bankLogoBucket, bankBO.getLogoSecond(), "", "", ""),
                        QiniuUtil.generateDownloadURL(bankLogoBucket, bankBO.getBackgroundLogo(), "", "", ""),
                        bankBO.getLogoColor()));
            });
        }
        return bos;
    }

    /**
     * 校验卡信息
     *
     * @param bo
     * @throws Exception
     */
    private void checkBindBankCard(UserBankcardBO bo) throws Exception {
        String bankCard = bo.getCode();
        String encodeCard = encryptBankCard(bankCard.replaceAll(" ", ""));
        SaleUserBankcardExample example = new SaleUserBankcardExample();
        example.createCriteria().andCodeEqualTo(encodeCard).andEnableEqualTo(true).andDeleteMarkEqualTo(false);
        List<SaleUserBankcard> lists = userBankcardMapper.selectByExample(example);
        if (CollectionUtils.isNotEmpty(lists)) {
            LOGGER.info("This card has been binding, please check your bank card number, binding again.");
            throw new BusinessException("此银行卡已被绑定，请核对您的银行卡号，再次绑定。");
        }
    }

    /**
     * 加密银行卡号
     *
     * @param cardCode 银行卡号
     * @return 加密之后卡号
     */
    public String encryptBankCard(String cardCode) {
        String key = autoConfConstant.getBankSecureKey();
        return Encodes.encryptAES(cardCode, key);
    }

    /**
     * 解密银行卡号
     *
     * @param cardCode 银行卡号
     * @return 解密之后卡号
     */
    public String decryptBankCard(String cardCode) {
        String key = autoConfConstant.getBankSecureKey();
        if (StringUtils.isNotBlank(cardCode)) {
            return Encodes.decryptAES(cardCode, key);
        }
        return "";
    }

    @Override
    public Map<String, String> checkBankCard(String card) throws Exception {
        LOGGER.info("UserBankcardServiceImpl.checkBankCard param card: {}", card);
        TreeMap<String, Object> treeMap = new TreeMap<String, Object>();
        treeMap.put("cardno", card.replaceAll(" ", ""));
        //第一步 生成AESkey及encryptkey
        String AESKey = PaymobileUtils.buildAESKey();
        String encryptkey = PaymobileUtils.buildEncyptkey(AESKey);
        //第二步 生成data
        String data = PaymobileUtils.buildData(treeMap, AESKey);
        //第三步 http请求，银行卡信息查询接口的请求方式为POST
        String merchantaccount = PaymobileUtils.getMerchantaccount();
        String url = PaymobileUtils.getRequestUrl(PaymobileUtils.CHECKBANKCARDAPI_NAME);
        TreeMap<String, String> responseMap = PaymobileUtils.httpPost(url, merchantaccount, data, encryptkey);
        //第四步 判断请求是否成功
        if (responseMap.containsKey("error_code")) {
            LOGGER.info("Calling card validation exception");
            throw new BusinessException(responseMap.get("error_msg"));
        }
        //第五步 请求成功，则获取data、encryptkey，并将其解密
        String data_response = responseMap.get("data");
        String encryptkey_response = responseMap.get("encryptkey");
        TreeMap<String, String> responseDataMap = PaymobileUtils.decrypt(data_response, encryptkey_response);
        //第六步 sign验签
        if (!PaymobileUtils.checkSign(responseDataMap)) {
            LOGGER.info("Failed to sign attestation");
            throw new BusinessException("sign验签失败");
        }
        //第七步 判断请求是否成功
        if (responseMap.containsKey("error_code")) {
            LOGGER.info("Calling card validation exception");
            throw new BusinessException(responseMap.get("error_msg"));
        }
        // 业务处理
        String cardtype = responseDataMap.get("cardtype");
        String bankname = responseDataMap.get("bankname");
        String isvalid = responseDataMap.get("isvalid");
        String bankcode = responseDataMap.get("bankcode");
        // 判断是否为借记卡
        if (!cardtype.equals(YeepayCardTypeEnum.DEBIT.getValue())) {
            LOGGER.info("Card type is not a debit card");
            throw new BusinessException("卡类型不是借记卡");
        }
        // 卡是否可用
        if (!isvalid.equals(YeepayCardValidEnum.YES.getValue())) {
            LOGGER.info("This card is not available");
            throw new BusinessException("此卡不可用");
        }
        Map<String, String> map = new HashMap<>();
        map.put("bankname", bankname);
        map.put("cardtype", YeepayCardTypeEnum.getByValue(cardtype).getText());
        map.put("bankcode", bankcode);
        return map;
    }
}
